package cn.jbolt.core.service;

import cn.hutool.core.io.FileUtil;
import cn.jbolt.core.base.JBoltMsg;
import cn.jbolt.core.bean.Option;
import cn.jbolt.core.cache.JBoltDictionaryCache;
import cn.jbolt.core.cache.JBoltDictionaryTypeCache;
import cn.jbolt.core.cache.JBoltPermissionCache;
import cn.jbolt.core.common.enums.DictionaryTypeMode;
import cn.jbolt.core.common.enums.JBoltSystemLogTargetType;
import cn.jbolt.core.db.sql.Sql;
import cn.jbolt.core.kit.JBoltUserKit;
import cn.jbolt.core.model.Dictionary;
import cn.jbolt.core.model.DictionaryType;
import cn.jbolt.core.model.Permission;
import cn.jbolt.core.service.base.JBoltBaseService;
import cn.jbolt.core.util.JBoltArrayUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.aop.Inject;
import com.jfinal.kit.Kv;
import com.jfinal.kit.Okv;
import com.jfinal.kit.Ret;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.IAtom;
import com.jfinal.plugin.activerecord.Record;

import java.sql.SQLException;
import java.util.*;

/**
 * 字典Service
 * @ClassName:  DictionaryService
 * @author: JFinal学院-小木 QQ：909854136
 * @date:   2019年11月9日
 */
public class JBoltDictionaryService extends JBoltBaseService<Dictionary>{
	protected Dictionary dao=new Dictionary().dao();
	@Inject
	protected JBoltDictionaryTypeService jboltDictionaryTypeService;
	@Override
	protected Dictionary dao() {
		return dao;
	}
	/**
	 * 根据类型获得数据字典数据列表
	 * @param typeId
	 * @return
	 */
	public List<Dictionary> getListByTypeId(Long typeId, Boolean enable) {
		return find(selectSql().eq(TYPE_ID, typeId).eq(ENABLE,enable));
	}
	/**
	 * 根据类型获得数据字典数据列表
	 * @param typeKey
	 * @return
	 */
	public List<Dictionary> getListByTypeKey(String typeKey) {
		return find(selectSql().eq(TYPE_KEY, typeKey));
	}
	/**
	 * 根据类型获得数据字典数据列表
	 * @param typeKey
	 * @param enable
	 * @return
	 */
	public List<Dictionary> getListByTypeKey(String typeKey,Boolean enable) {
		return find(selectSql().eq(TYPE_KEY, typeKey).eq(ENABLE,enable));
	}
	/**
	 * 根据类型获得数据字典数据列表
	 * @param typeId
	 * @param keywords
	 * @return
	 */
	public List<Dictionary> getAdminListByTypeId(Long typeId,String keywords,Boolean enable) {
		return getListByTypeId(typeId,keywords,true,enable,false);
	}
	/**
	 * 根据类型获得数据字典数据列表
	 * @param typeKey
	 * @param keywords
	 * @param enable
	 * @return
	 */
	public List<Dictionary> getListByTypeKey(String typeKey,String keywords,Boolean enable,boolean isApiDatas) {
		return getListByTypeKey(typeKey,keywords,true,enable,isApiDatas);
	}

	/**
	 * 根据类型获得数据字典数据列表
	 * @param typeKey
	 * @param needSubItems
	 * @param enable
	 * @return
	 */
	public List<Dictionary> getListByTypeKey(String typeKey,boolean needSubItems,Boolean enable) {
		return getListByTypeKey(typeKey,null,needSubItems,enable);
	}
	/**
	 * 根据类型获得数据字典数据列表
	 * @param typeId
	 * @param needSubItems
	 * @param enable
	 * @param isApiDatas
	 * @return
	 */
	public List<Dictionary> getListByTypeId(Long typeId,boolean needSubItems,Boolean enable,boolean isApiDatas) {
		return getListByTypeId(typeId,null,needSubItems,enable,isApiDatas);
	}
	/**
	 * 根据类型获得数据字典数据列表
	 * @param typeId
	 * @param keywords
	 * @param needSubItems
	 * @param enable
	 * @param isApiDatas
	 * @return
	 */
	public List<Dictionary> getListByTypeId(Long typeId,String keywords,boolean needSubItems,Boolean enable,boolean isApiDatas) {
		return getListByTypeId(typeId, keywords, needSubItems,enable,null,isApiDatas);
	}
	/**
	 * 根据类型获得数据字典数据列表
	 * @param typeKey
	 * @param keywords
	 * @param needSubItems
	 * @param enable
	 * @return
	 */
	public List<Dictionary> getListByTypeKey(String typeKey,String keywords,boolean needSubItems,Boolean enable,boolean isApiDatas) {
		return getListByTypeKey(typeKey, keywords, needSubItems,enable,null,isApiDatas);
	}
	/**
	 * 根据类型获得数据字典数据列表
	 * @param typeKey
	 * @param keywords
	 * @param needSubItems
	 * @param enable
	 * @param exceptIds 指定ID数组 排除
	 * @return
	 */
	public List<Dictionary> getListByTypeKey(String typeKey,String keywords,boolean needSubItems,Boolean enable,Long[] exceptIds,boolean isApiDatas) {
		DictionaryType type = JBoltDictionaryTypeCache.me.getByKey(typeKey);
		if(type == null) {return null;}
		return getListByTypeId(type.getId(), keywords, needSubItems, enable,exceptIds,isApiDatas);
	}
	/**
	 * 根据类型获得数据字典数据列表
	 * @param typeId
	 * @param keywords
	 * @param needSubItems
	 * @param enable
	 * @param exceptIds 指定ID数组 排除
	 * @return
	 */
	public List<Dictionary> getListByTypeId(Long typeId,String keywords,boolean needSubItems,Boolean enable,Long[] exceptIds,boolean isApiDatas) {
		if(notOk(typeId)){
			return null;
		}
		Sql sql = selectSql();
		sql.eq(TYPE_ID, typeId);
		sql.eq(ENABLE,enable);
		if(!needSubItems){
			//如果不需要下级 就只读取上级
			sql.eq(PID, 0);
		}
		if(isOk(exceptIds)) {
			for (Long exceptId : exceptIds) {
				sql.notEq(ID, exceptId);
			}
		}
		sql.likeMulti(keywords, NAME,SN);
		sql.asc(SORT_RANK);
		if(isApiDatas){
			sql.select(Dictionary.ID,Dictionary.NAME,Dictionary.PID,Dictionary.SN,Dictionary.SORT_RANK,Dictionary.TYPE_KEY,Dictionary.ENABLE);
		}
		List<Dictionary> dictionarys = find(sql);

		if(isOk(dictionarys) && needSubItems && notOk(keywords)){
			return convertToModelTree(dictionarys, ID, PID, (p)->notOk(p.getPid()));
		}
		return dictionarys;
	}

	/**
	 * 根据类型和父id获得数据字典数据列表
	 * @param typeId
	 * @param pid
	 * @param enable
	 * @return
	 */
	public List<Dictionary> getSonListByTypeId(Long typeId,Long pid,Boolean enable) {
		if(notOk(typeId)||notOk(pid)){
			return Collections.emptyList();
		}
		Okv okv = Okv.by(TYPE_ID, typeId).set(PID, pid);
		if(enable!=null){
			okv.set(ENABLE,enable);
		}
		return getCommonList(okv);
	}

	/**
	 * 根据ID删除字典数据
	 * @param id
	 * @param cancelCheckSystemCanDeleteEnable
	 * @return
	 */
	public Ret deleteDictionaryById(Long id,boolean cancelCheckSystemCanDeleteEnable) {
		Ret ret=null;
		if(cancelCheckSystemCanDeleteEnable){
			Dictionary dictionary = findById(id);
			dictionary.cancelSystemDictionaryDeleteEnable();
			boolean success = dictionary.delete();
			ret = success?successWithData(dictionary):fail();
		}else{
			ret = deleteById(id);
		}
		if(ret.isOk()){
			//删除子数据以及缓存
			deleteByPid(id);
			Dictionary dictionary=ret.getAs("data");
			//删除后需要把此数据之后的数据更新顺序
			updateSortRankAfterDelete(Okv.by(TYPE_ID, dictionary.getTypeId()).set(PID,dictionary.getPid()),dictionary.getSortRank());
			//增加系统日志
			addDeleteSystemLog(id, JBoltUserKit.getUserId(),dictionary.getName());
		}
		return ret;
	}

	@Override
	public String checkCanDelete(Dictionary dictionary, Kv kv) {
		return super.checkCanDelete(dictionary, kv);
	}

	/**
	 * 添加多个
	 * @param msg
	 * @param typeId
	 * @param pid
	 * @param nameStr
	 * @param snStr
	 * @return
	 */
	private boolean saveAll(StringBuilder msg,Long typeId,Long pid, String nameStr, String snStr) {
		String[] nameOlds = JBoltArrayUtil.from(nameStr," ");
		if(notOk(nameOlds)) {msg.append(JBoltMsg.PARAM_ERROR);return false;}
		String[] names = JBoltArrayUtil.from3(nameStr," ");
		if(notOk(names)) {msg.append(JBoltMsg.PARAM_ERROR);return false;}
		if(nameOlds.length!=names.length) {
			msg.append("字典数据名称里存在重复数据，请检查");
			return false;
		}
		int size=names.length;
		int snSize=0;
		String[] snsOld = JBoltArrayUtil.from(snStr," ");
		String[] sns = JBoltArrayUtil.from3(snStr," ");
		if(isOk(snsOld)&&isOk(sns)) {
			if(snsOld.length!=sns.length) {
				msg.append("编号里存在重复数据，请检查");
				return false;
			}
			snSize=sns.length;
		}

		if(snSize>0&&snSize!=size) {
			msg.append("名称和编号数量不一致，请检查");
			return false;
		}
		Ret ret;
		String name,sn;
		List<Dictionary> dics=new ArrayList<Dictionary>();
		for(int i=0;i<size;i++){
			name=names[i];
			sn=null;
			if(snSize==size) {
				sn=sns[i];
			}
			dics.add(new Dictionary().setTypeId(typeId).setPid(pid).setName(name).setSn(sn).setEnable(true));
		 }
		for(Dictionary dictionary:dics) {
			ret=save(dictionary);
			if(ret.isFail()) {
				msg.append(ret.getStr("msg")).append("<br/>");
			}
		}
		return msg.length()==0;
	}

	/**
	 * 保存字典数据
	 * @param dictionary
	 * @return
	 */
	public Ret save(Dictionary dictionary) {
		if(dictionary==null||isOk(dictionary.getId())||notOk(dictionary.getName())||notOk(dictionary.getTypeId())){
			return fail(JBoltMsg.PARAM_ERROR);
		}
		String name=dictionary.getName().trim();
		dictionary.setName(name);
		String sn=dictionary.getSn();
		if(name.contains(" ")){
			if(isOk(sn)) {
				sn=sn.trim();
			}
			dictionary.setSn(sn);
			StringBuilder msg=new StringBuilder();
			boolean success=tx(new IAtom() {
				@Override
				public boolean run() throws SQLException {
					return saveAll(msg,dictionary.getTypeId(),dictionary.getPid(),dictionary.getName(),dictionary.getSn());
				}
			});
			return success?SUCCESS:fail(msg.toString());
		}
		if(name.length()>100) {
			return fail("此名称["+name+"]长度不能超过100字符，请更正");
		}
		if(isOk(sn)&&sn.length()>100) {
			return fail("此编号["+sn+"]长度不能超过100字符，请更正");
		}
		if (existName(LONG_MINUS_1,name,dictionary.getTypeId(),dictionary.getPid())) {
			return fail("此名称["+name+"]已经存在，请更正");
		}
		if (isOk(sn)&&existSn(LONG_MINUS_1,sn,dictionary.getTypeId())) {
			return fail("此编号["+sn+"]已经存在，请更正");
		}

		if(dictionary.getPid()==null){
			dictionary.setPid(LONG_0);
		}
		dictionary.setSortRank(getNextSortRank(Okv.by(TYPE_ID, dictionary.getTypeId()).set(PID,dictionary.getPid())));
		dictionary.setTypeKey(JBoltDictionaryTypeCache.me.getKey(dictionary.getTypeId()));
		if(dictionary.getEnable()==null){
			dictionary.setEnable(true);
		}
		boolean success=dictionary.save();
		if(success){
			//增加系统日志
			addSaveSystemLog(dictionary.getId(), JBoltUserKit.getUserId(),dictionary.getName());
		}
		return ret(success);
	}

	/**
	 * 修改字典数据
	 * @param dictionary
	 * @return
	 */
	public Ret update(Dictionary dictionary) {
		if(dictionary==null||notOk(dictionary.getId())||notOk(dictionary.getName())||notOk(dictionary.getTypeId())){
			return fail(JBoltMsg.PARAM_ERROR);
		}
		if(dictionary.getPid()==null){
			dictionary.setPid(LONG_0);
		}else if(dictionary.getPid().intValue()==dictionary.getId()) {
			return fail("上级不能是自己，请更正");
		}
		Dictionary db=findById(dictionary.getId());
		if(db == null){
			return fail(JBoltMsg.DATA_NOT_EXIST);
		}
		Boolean sort=dictionary.getBoolean("sort");
		if(sort == null || !sort){
			if(db.getIsBuildIn()){
				return fail("内置字典数据，不可修改");
			}
		}
		String name=dictionary.getName().trim();
		if (existName(dictionary.getId(),name,dictionary.getTypeId(),dictionary.getPid())) {
			return fail("此名称["+name+"]已经存在，请更正");
		}
		String sn=dictionary.getSn();
		if (isOk(sn)&&existSn(dictionary.getId(),sn,dictionary.getTypeId())) {
			return fail("此编号["+sn+"]已经存在，请更正");
		}
		dictionary.setName(name);
		if(isOk(sn)) {
			dictionary.setSn(sn.trim());
		}
		dictionary.setTypeKey(JBoltDictionaryTypeCache.me.getKey(dictionary.getTypeId()));
		boolean success=dictionary.update();
		if(success){
			//增加系统日志

			if(isOk(sort)&&sort) {
				addUpdateSystemLog(dictionary.getId(), JBoltUserKit.getUserId(),dictionary.getName(),"的顺序");
			}else {
				addUpdateSystemLog(dictionary.getId(), JBoltUserKit.getUserId(),dictionary.getName());
			}

		}
		return ret(success);
	}


	/**
	 * 判断字典名是否存在
	 * @param excludedId 排除指定ID
	 * @param name
	 * @param typeId
	 * @param pid
	 * @return
	 */
	public boolean existName(Long excludedId,String name,Long typeId,Long pid) {
		if(hasNotOk(name,typeId)){
			throw new RuntimeException(JBoltMsg.PARAM_ERROR);
		}
		Sql sql = selectSql().eqQM(NAME,TYPE_ID).eq(PID, pid);
		if(isOk(excludedId)){
			sql.idNotEq(excludedId);
		}
		return exists(sql,name.trim(),typeId);
	}
	/**
	 * 判断字典sn编号是否存在
	 * @param excludedId 排除指定ID
	 * @param sn
	 * @param typeId
	 * @return
	 */
	public boolean existSn(Long excludedId,String sn,Long typeId) {
		if(hasNotOk(sn,typeId)){
			throw new RuntimeException(JBoltMsg.PARAM_ERROR);
		}
		Sql sql = selectSql().eqQM(SN,TYPE_ID);
		if(isOk(excludedId)){
			sql.idNotEq(excludedId);
		}
		return exists(sql,sn.trim(),typeId);
	}
	/**
	 * 根据Type查询符合条件的个数
	 * @param typeId
	 * @return
	 */
	public int getCountByTypeId(Long typeId) {
		if(notOk(typeId)){return 0;}
		return getCount(Okv.by(TYPE_ID, typeId));
	}

	public String getCacheNames(String ids) {
		if(notOk(ids)){return "未设置";}
		String[] idsArray=JBoltArrayUtil.from(ids, ",");
		if(idsArray.length == 0){return "未设置";}
		StringBuilder sb=new StringBuilder();
		int index=0;
		for(String id:idsArray){
			if(isOk(id)){
				Dictionary dictionary=JBoltDictionaryCache.me.get(Long.parseLong(id));
				if(dictionary!=null){
					if(isOk(dictionary.getPid())&&JBoltDictionaryTypeCache.me.getModeLevel(dictionary.getTypeId())== DictionaryTypeMode.LEVEL_MULTI.getValue()){
						String pname=JBoltDictionaryCache.me.getName(dictionary.getPid());
						sb.append((StrKit.notBlank(pname)?(pname+"-"):"")+dictionary.getName());
					}else{
						sb.append(dictionary.getName());
					}
					if(index<idsArray.length-1){
						sb.append("，");
					}

				}

			}
			index++;
		}
		return sb.toString();
	}

	public boolean checkTypeInUse(Long typeId) {
		int count=getCountByTypeId(typeId);
		return count>0;
	}

	/**
	 * 根据类型获得字典数据_只获得一级
	 * @param typeKey
	 * @return
	 */
	public List<Dictionary> getRootListByTypeKey(String typeKey,Boolean enable,boolean isApiDatas) {
		DictionaryType dictionaryType=JBoltDictionaryTypeCache.me.getByKey(typeKey);
		if(dictionaryType==null){return Collections.emptyList();}
		return getListByTypeId(dictionaryType.getId(),null,false,enable,isApiDatas);
	}

	/**
	 * 根据类型Key和PID获得字典数据
	 * @param typeKey
	 * @param pid
	 * @return
	 */
	public List<Dictionary> getSonListByTypeKey(String typeKey,Long pid,Boolean enable) {
		if(notOk(typeKey)||notOk(pid)) {return Collections.emptyList();}
		DictionaryType dictionaryType=JBoltDictionaryTypeCache.me.getByKey(typeKey);
		if(dictionaryType==null){return Collections.emptyList();}
		return getSonListByTypeId(dictionaryType.getId(),pid,enable);
	}
	/**
	 * 上移
	 * @param id
	 * @return
	 */
	public Ret doUp(Long id) {

		Dictionary dictionary=findById(id);
		if(dictionary==null){
			return fail(JBoltMsg.DATA_NOT_EXIST);
		}
		Integer rank=dictionary.getSortRank();
		if(rank==null||rank<=0){
			return fail("顺序需要初始化");
		}
		if(rank==1){
			return fail("已经是第一个");
		}
		Dictionary upDictionary=findFirst(Okv.by(SORT_RANK, rank-1).set(TYPE_ID, dictionary.getTypeId()) .set(PID, dictionary.getPid()));
		if(upDictionary==null){
			return fail("顺序需要初始化");
		}
		upDictionary.setSortRank(rank);
		dictionary.setSortRank(rank-1);
		upDictionary.put("sort", true);
		dictionary.put("sort", true);
		update(upDictionary);
		update(dictionary);
		return SUCCESS;

	}


	/**
	 * 改变顺序
	 * @param id
	 * @param oriPid 原父节点
	 * @param newPid 新父节点
	 * @param oriRank 原顺序
	 * @param newRank 新顺序
	 * @return
	 */
	public Ret changeSortRank(Long id, Long oriPid, Long newPid,  Integer oriRank, Integer newRank) {
		if (Objects.equals(oriPid, newPid) && Objects.equals(oriRank, newRank)) {
			return SUCCESS;
		}
		Dictionary dict = findById(id);
		if (Objects.equals(oriPid, newPid)) {
			//在原父元素内部移动
			updateSortRankByPid(dict.getTypeId(), id,oriPid, oriRank, newRank );

		} else {
			updateSortRankByPid(dict.getTypeId(), id, oriPid, oriRank, null);
			updateSortRankByPid(dict.getTypeId(), id, newPid, null, newRank);
		}
		// 需要处理菜单缓存
		JBoltDictionaryCache.me.removeEnableDatasCacheByTypeId(dict.getTypeId());
		return SUCCESS;
	}

	private void updateSortRankByPid(Long typeId, Long id, Long pid, Integer oriRank, Integer newRank) {
		Sql sql = updateSql().eq(PID, pid).eq(Dictionary.TYPE_ID, typeId);
		if (newRank == null) {
			//newRank是null，代表它从原来的父元素里移出来了，原来排它后面的同级元素的顺序要-1，比如原来它排第6，后面789的元素现在变678了
			sql.gt(SORT_RANK, oriRank);
			sql.setSqlExpress(SORT_RANK, "sort_rank-1");
		} else if (oriRank == null) {

			// oriRank是null，代表它是新挪进来的，原来排它后面的同级元素的顺序要+1，比如它现在顺序是第6，原来678的就要变成789
			// 并且它的pid要变成新的pid

			sql.ge(SORT_RANK, newRank).or().eq(ID, id);
			sql.setSqlExpress(SORT_RANK, "if(id="+id+", "+newRank+", sort_rank+1)")
					.setSqlExpress(PID, "if(id="+id+", "+pid+", pid)");


		} else if (oriRank > newRank) {
			//向下移动了，比如 原来6，现在3，那么需要 >=3 &&  <6的顺序+1，原来 345变成 456，然后原来的6 变成3
			sql.ge(SORT_RANK, newRank).le(SORT_RANK, oriRank);
			sql.setSqlExpress(SORT_RANK, "if(sort_rank="+oriRank+","+newRank+",sort_rank+1)");
		} else {
			//向上移动, 比如原来3 ，现在6，那么需要 >3 && <=6的顺序-1，原来的 456变成 345，然后原来的3 变成6
			sql.ge(SORT_RANK, oriRank).le(SORT_RANK, newRank);
			sql.setSqlExpress(SORT_RANK, "if(sort_rank="+oriRank+","+newRank+",sort_rank-1)");
		}
		update(sql);
	}

	/**
	 * 下移
	 * @param id
	 * @return
	 */
	public Ret down(Long id) {
		Dictionary dictionary=findById(id);
		if(dictionary==null){
			return fail(JBoltMsg.DATA_NOT_EXIST);
		}
		Integer rank=dictionary.getSortRank();
		if(rank==null||rank<=0){
			return fail("顺序需要初始化");
		}
		int max=getCount(Okv.by(PID,dictionary.getPid()));
		if(rank==max){
			return fail("已经是最后一个");
		}
		Dictionary upDictionary=findFirst(Okv.by(SORT_RANK, rank+1).set(TYPE_ID, dictionary.getTypeId()).set(PID, dictionary.getPid()));
		if(upDictionary==null){
			return fail("顺序需要初始化");
		}
		upDictionary.setSortRank(rank);
		dictionary.setSortRank(rank+1);
		upDictionary.put("sort", true);
		dictionary.put("sort", true);
		update(upDictionary);
		update(dictionary);
		return SUCCESS;
	}

	/**
	 * 初始化排序
	 * @param typeId
	 */
	public Ret initRank(Long typeId){
		DictionaryType dictionaryType=jboltDictionaryTypeService.findById(typeId);
		if(dictionaryType==null) {
			return fail(JBoltMsg.DATA_NOT_EXIST);
		}
		List<Dictionary> parents=getCommonList(Okv.by(TYPE_ID, typeId).set(PID,0));
		if(parents.size()>0){
			for(int i=0;i<parents.size();i++){
				parents.get(i).setSortRank(i+1);
				List<Dictionary> sons=getSonListByTypeId(typeId, parents.get(i).getId(),null);
				if(sons.size()>0){
					for(int k=0;k<sons.size();k++){
						sons.get(k).setSortRank(k+1);
					}
					batchUpdate(sons);
				}
			}
			batchUpdate(parents);

			//添加日志
			addUpdateSystemLog(null, JBoltUserKit.getUserId(),"全部","初始化顺序");
		}
		return SUCCESS;

	}
	/**
	 * 获取不包含自己的列表
	 * @param typeId
	 * @param exceptId
	 * @param enable
	 * @return
	 */
	public List<Dictionary> getListByTypeIdWithoutSelf(Long typeId, Long exceptId,Boolean enable,boolean isApiDatas) {
		if(isOk(exceptId)) {
			return getListByTypeId(typeId, null,true,enable,new Long[] {exceptId},isApiDatas);
		}
		return getListByTypeId(typeId,null,enable,null,isApiDatas);
	}
	/**
	 * 一个字典分类修改了TypeKey后需要更新字典表数据的绑定
	 * @param typeId
	 * @param typeKey
	 */
	public void updateTypeKey(Long typeId, String typeKey) {
		update(updateSql().set(TYPE_KEY, typeKey).eq(TYPE_ID, typeId));
	}

	/**
	 * 清空分类下的字典数据
	 * @param typeId
	 * @return
	 */
	public Ret clearByTypeId(Long typeId) {
		if(notOk(typeId)) {return fail(JBoltMsg.PARAM_ERROR);}
		DictionaryType dictionaryType=jboltDictionaryTypeService.findById(typeId);
		if(dictionaryType==null) {
			return fail("指定字典分类"+JBoltMsg.DATA_NOT_EXIST);
		}
		Sql sql = selectSql().eqQM(TYPE_ID);
		//如果是系统内置 清空只清空扩展项目
		if(dictionaryType.getIsBuildIn()){
			sql.eq("is_build_in",FALSE);
		}
		dao().each(config -> {
			config.delete();
			return true;
		}, sql.toSql(),typeId);
		return SUCCESS;
	}
	/**
	 * 检测默认字典完整性并补齐和初始化缺失
	 * @return
	 */
	public Ret checkAndInit() {
		Ret ret = checkAndInit("dictionary_init.json",true);
		if(ret.isFail()) {
			return ret;
		}
		return checkAndInit("extend_dictionary_init.json",false);
	}
	/**
	 * 检测并初始化指定的数据字典
	 * @param fileName
	 * @param isBuildIn
	 * @return
	 */
	private Ret checkAndInit(String fileName,boolean isBuildIn) {
		if(!FileUtil.exist(fileName)) {
			return fail("未找到"+fileName+"文件不存在");
		}
		String json=FileUtil.readUtf8String(fileName);
		if(notOk(json)) {
			return fail(fileName+"文件里未检测到数据");
		}
		JSONArray dicTypes=JSON.parseArray(json);
		if(dicTypes==null||dicTypes.isEmpty()) {
			LOG.warn(fileName+"文件里未检测到数据");
			return SUCCESS;
		}

		int size=dicTypes.size();
		JSONObject jsonObject;
		DictionaryType type;
		JSONArray dics;
		String typeKey;
		for(int i=0;i<size;i++) {
			jsonObject=dicTypes.getJSONObject(i);
			typeKey = jsonObject.getString("typeKey");
			//数据库里找 没找到就save
			type =jboltDictionaryTypeService.findByTypeKey(typeKey);
			if(type==null) {
				type = jsonObject.toJavaObject(DictionaryType.class);
				if(isBuildIn || type.getIsBuildIn() == null){
					type.setIsBuildIn(isBuildIn);
				}
				if(notOk(type.getModeLevel())){
					type.setModeLevel(1);
				}
				type.save();
			}else{
				if(type.getIsBuildIn() == null){
					type.setIsBuildIn(isBuildIn);
					type.update();
				}
			}
			List<Dictionary> saveList =  new ArrayList<>();
			dics=jsonObject.getJSONArray("dics");
			checkAndInit(type,saveList,0L,dics,type.getIsBuildIn());
			if(isOk(saveList)){
				batchSave(saveList);
			}
		}
		return SUCCESS;
	}


	/**
	 * 检测缺失字典
	 * @param type
	 * @param saveList
	 * @param pid
	 * @param dicArray
	 * @param isBuildIn
	 */
	private void checkAndInit(DictionaryType type,List<Dictionary> saveList,Long pid, JSONArray dicArray,boolean isBuildIn) {
		if(dicArray==null || dicArray.size() == 0){
			return;
		}
		int size = dicArray.size();
		JSONObject dicObj;
		JSONArray items;
		Dictionary dic;
		Dictionary dbDic;
		for(int i=0;i<size;i++){
			dicObj = dicArray.getJSONObject(i);
			//转 model
			dic=dicObj.toJavaObject(Dictionary.class);
			dbDic = findFirst(selectSql().eq("type_id",type.getId()).eq("pid",pid==null?0L:pid).eq("sn",dic.getSn()));
			if(dbDic == null){
				dic.setPid(pid);
				if(dic.getIsBuildIn() == null){
					dic.setIsBuildIn(isBuildIn);
				}
				dic.setTypeId(type.getId());
				dic.setTypeKey(type.getTypeKey());
				dic.autoProcessIdValue();
				dic.checkNeedAutoProcessCreateTime();
				//save(dic);
				saveList.add(dic);
			}else{
				dic.setId(dbDic.getId());
			}
			if(type.getModeLevel()!=1){
				//拿到Items
				items = dicObj.containsKey("items")?dicObj.getJSONArray("items"):null;
				checkAndInit(type,saveList,dic.getId(),items,isBuildIn);
			}
		}

	}
	/**
	 * 根据父节点sn获取pid然后查询子节点数据
	 * @param typeKey
	 * @param psn
	 * @param enable
	 * @return
	 */
	public List<Dictionary> getSonListByTypeKeyAndPsn(String typeKey,String psn,Boolean enable) {
		if(notOk(typeKey)||notOk(psn)) {return Collections.emptyList();}
		Dictionary parentDic=JBoltDictionaryCache.me.getBySn(typeKey, psn);
		if(parentDic==null) {
			return Collections.emptyList();
		}
		return getSonListByTypeKey(typeKey, parentDic.getId(),enable);
	}
	@Override
	protected int systemLogTargetType() {
		return JBoltSystemLogTargetType.DICTIONARY.getValue();
	}

	/**
	 * 将指定类型下的字典数据 设置enable
	 * @param typeId
	 * @param enable
	 */
	public void changeEnableByTypeId(Long typeId,boolean enable) {
		if(typeId == null){throw new RuntimeException("未指定有效的字典类型");}
		//设置指定列enable 为false
		changeColumnBoolean(ENABLE,-1,selectSql().select(ID,ENABLE).eq(TYPE_ID,typeId),enable);
		//循环处理缓存删除
		dao().each(m->{
			m.deleteCacheById(m.getId());
			return true;
		},selectSql().selectId().eqQM(TYPE_ID).toSql(),typeId);
	}

	@Override
	protected String afterToggleBoolean(Dictionary dic, String column, Kv kv) {
		if(column.equalsIgnoreCase(ENABLE)){
			DictionaryType type = JBoltDictionaryTypeCache.me.get(dic.getTypeId());
			if(type == null){
				return "字典所属类型不存在";
			}
			//多级的需要执行递归
			if (type.getModeLevel().intValue() == DictionaryTypeMode.LEVEL_MULTI.getValue()){
				changeSonsEnableByTypeId(dic.getId(),dic.getTypeId(),dic.getEnable().booleanValue());
			}
		}
		return null;
	}

	/**
	 * 循环遍历设置enable
	 * @param pid
	 * @param enable
	 */
	private void changeEnableByPid(Long pid,boolean enable){
		if(notOk(pid)){throw new RuntimeException("未指定有效的字典pid");}
		Dictionary dictionary = findById(pid);
		if(dictionary == null){
			throw new RuntimeException("指定字典数据不存在");
		}
		//调用递归处理子数据节点
		changeSonsEnableByTypeId(pid,dictionary.getTypeId(),enable);
	}


	/**
	 * 将指定类型下的字典子数据 设置enable
	 * @param typeId
	 * @param enable
	 */
	public void changeSonsEnableByTypeId(Long pid,Long typeId,boolean enable) {
		if(notOk(pid)){throw new RuntimeException("未指定有效的父节点");}
		if(typeId == null){throw new RuntimeException("未指定有效的字典类型");}
		//设置指定列enable 为false
		changeColumnBoolean(ENABLE,-1,selectSql().select(ID,ENABLE).eq(PID,pid).eq(TYPE_ID,typeId),enable);
		//循环处理缓存删除
		dao().each(m->{
			m.deleteCacheById(m.getId());
			//递归调用
			changeSonsEnableByTypeId(m.getId(),typeId,enable);
			return true;
		},selectSql().selectId().eqQM(PID,TYPE_ID).toSql(),pid,typeId);
	}

	/**
	 * 获取一个类型下的字典数据的map
	 * @param typeKey
	 * @param keyColumn
	 * @return
	 */
	public Map<String,Dictionary> getDictionaryMapByTypeKey(String typeKey, String keyColumn){
		List<Dictionary> dics = getListByTypeKey(typeKey);
		if(notOk(dics)){return null;}
		Map<String,Dictionary> map = new HashMap<>();
		for(Dictionary dic:dics){
			map.put(dic.getStr(keyColumn),dic);
		}
		return map;
	}

	/**
	 * 获取一个类型下的字典数据的map
	 * @param typeKey
	 * @param keyColumn
	 * @param valueColumn
	 * @return
	 */
	public Map<String,String> getDictionaryMapByTypeKey(String typeKey,String keyColumn,String valueColumn){
		List<Dictionary> dics = getListByTypeKey(typeKey);
		if(notOk(dics)){return null;}
		Map<String,String> map = new HashMap<>();
		for(Dictionary dic:dics){
			map.put(dic.getStr(keyColumn),dic.getStr(valueColumn));
		}
		return map;
	}

	@Override
	public String checkCanToggle(Dictionary dictionary, String column, Kv kv) {
		if(column.equals(ENABLE) && dictionary.getEnable()){
			Boolean isBuildIn = dictionary.getIsBuildIn();
			if(isBuildIn!=null && isBuildIn){
				return "系统内置字典数据，不可禁用";
			}
		}
		return null;
	}

}
